﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;

namespace SC
{
    public class SocketServer
    {
        #region socket
        //用于通信的Socket
        Socket socketSend;
        //用于监听的SOCKET
        Socket socketWatch;
        //将远程连接的客户端的IP地址和Socket存入集合中
        public Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
        //创建监听连接的线程
        Thread AcceptSocketThread;
        //接收客户端发送消息的线程
        Thread threadReceive;

        /// <summary>
        /// 服务器配置文件
        /// </summary>
        public Common.ServerProfile serverProfile;

        public delegate void ClientConnectedEvent(string ip);
        public ClientConnectedEvent clientConnectedEvent;

        public delegate void RecvEvent(Socket socketSend,MessageType messageType,byte[] data);
        public RecvEvent recvEvent;

        public delegate void CheckBeatEvent();
        public CheckBeatEvent checkBeatEvent;

        public Dictionary<string, bool> heartBeatDic = new Dictionary<string, bool>();

        System.Threading.Timer heartBeatTimer;

        public SocketServer()
        {
            serverProfile = new Common.ServerProfile(true);
            Start(serverProfile);
        }

        /// <summary>
        /// 等待客户端的连接，并且创建与之通信用的Socket
        /// </summary>
        /// <param name="obj"></param>
        private void StartListen(object obj)
        {
            heartBeatTimer = new System.Threading.Timer(ResetHertBeatDic, null, 5000, 5000);
            Socket socketWatch = obj as Socket;
            while (true)
            {
                try
                {
                    //等待客户端的连接，并且创建一个用于通信的Socket
                    socketSend = socketWatch.Accept();
                    //获取远程主机的ip地址和端口号
                    string strIp = socketSend.RemoteEndPoint.ToString();

                    if (!dicSocket.ContainsKey(strIp))
                    {
                        dicSocket.Add(strIp, socketSend);
                        //this.cmb_Socket.Invoke(setCmbCallBack, strIp);
                        //this.dSkinListBox1.Invoke(setCmbCallBack, strIp);

                        Common.Log.Info("Client Connect " + IPAddress.Parse(((IPEndPoint)socketSend.RemoteEndPoint).Address.ToString()) + "on port number " + ((IPEndPoint)socketSend.RemoteEndPoint).Port.ToString());

                        if (clientConnectedEvent != null)
                        {
                            clientConnectedEvent(strIp);
                        }

                        //定义接收客户端消息的线程
                        Thread threadReceive = new Thread(new ParameterizedThreadStart(Receive));
                        threadReceive.IsBackground = true;
                        threadReceive.Start(socketSend);
                    }

                }
                catch (Exception ex)
                {
                    Common.Log.Error(ex.Message);
                }


            }
        }
        
        /// <summary>
        /// 重置心跳状态
        /// </summary>
        public void ResetHertBeatDic(object state)
        {
            //发送检测心跳事件
            if (checkBeatEvent != null)
            {
                checkBeatEvent();
            }
            //重置心跳

            String[] keyArr = heartBeatDic.Keys.ToArray<String>();
            foreach(string key in keyArr)
            {
                heartBeatDic[key] = false;
            }
        }


        /// <summary>
        /// 服务器端不停的接收客户端发送的消息
        /// </summary>
        /// <param name="obj"></param>
        private void Receive(object obj)
        {
            try
            {
                Socket socketSend = obj as Socket;

                while (true)
                {
                    if(!socketSend.Connected)
                    {
                        break;
                    }

                    byte[] msgType, objBuf;
                    SC.MessagePack.DeserializeObjBuf(socketSend, out msgType, out objBuf);
                    if (objBuf != null && objBuf.Length > 0)
                    {
                        MessageType messageType = (MessageType)BitConverter.ToInt32(msgType, 0);

                        if (recvEvent != null)
                        {
                            recvEvent(socketSend, messageType, objBuf);
                        }
                    }
                }
            }
            catch (SocketException ex)
            {
                Common.Log.Error(ex.Message);
            }

        }


        private void Start(Common.ServerProfile serverProfile)
        {
            //开启socket服务
            try
            {
                
                if (0==serverProfile.serverPort)
                {
                    throw new EvaluateException("端口号不能为空");
                }

                if (socketWatch == null)
                {
                    //当点击开始监听的时候 在服务器端创建一个负责监听IP地址和端口号的Socket
                    socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                }

                //获取ip地址
                IPAddress iPAddress = IPAddress.Parse(serverProfile.serverIp.Trim());

                //创建端口号
                IPEndPoint point = new IPEndPoint(iPAddress, serverProfile.serverPort);

                if (!socketWatch.IsBound)
                {
                    socketWatch.Bind(point);
                }

                //this.txt_Log.AppendText("监听成功" + " \r \n");

                //开始监听:设置最大可以同时连接多少个请求
                socketWatch.Listen(1000);

                //创建线程
                AcceptSocketThread = new Thread(new ParameterizedThreadStart(StartListen));
                AcceptSocketThread.IsBackground = true;
                AcceptSocketThread.Start(socketWatch);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message+"请检查配置文件 common.ini");

                Common.Log.Error(ex.Message+"请检查配置文件 common.ini");

                Application.Exit();
            }

            //folderassets.LoadDir();


            SC.BroadCastServer.Start(serverProfile);
        }

        public void CloseClient(string clientkey)
        {
            if (dicSocket.ContainsKey(clientkey))
            {
                dicSocket[clientkey].Disconnect(false);
                dicSocket[clientkey].Close();
                Common.Log.Info(clientkey+"正常关闭");
            }
        }

        public  void Close()
        {
            if (socketWatch != null)
            {
                socketWatch.Close();
                socketWatch = null;
            }
            if (socketSend != null)
            {
                socketSend.Close();
                socketSend = null;
            }
            //终止线程
            if (AcceptSocketThread != null)
            {
                AcceptSocketThread.Abort();
                AcceptSocketThread = null;
            }
            if (threadReceive != null)
            {
                threadReceive.Abort();
                threadReceive = null;
            }
        }
        #endregion
    }
}
